﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Syncfusion.WinForms.DataGrid;

namespace NetStat.UI
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            groupColumnDescription = new GroupColumnDescription() {ColumnName = "ProcessName"};
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {

            GetNetStatData();
        }

        private GroupColumnDescription groupColumnDescription;
        private List<NetStatLine> netStatLines;

        private void GetNetStatData()
        {
            btnExport.Enabled = false;
            btnRefresh.Enabled = false;
            StartProcess();
            Task.Factory.StartNew(() =>
            {
                
                var stateList = new List<NetStatLine>();

                try
                {
                    using (Process p = new Process())
                    {

                        p.StartInfo.FileName = "cmd.exe";
                        p.StartInfo.UseShellExecute = false;
                        p.StartInfo.RedirectStandardInput = true;
                        p.StartInfo.RedirectStandardOutput = true;
                        p.StartInfo.RedirectStandardError = true;
                        p.StartInfo.CreateNoWindow = true;
                        p.Start();
                        //查看本机端口占用情况
                        p.StandardInput.WriteLine(" netstat -ano ");
                        p.StandardInput.WriteLine("exit");
                        //
                        using (StreamReader reader = p.StandardOutput)
                        {
                            string strLine = reader.ReadLine(); //每次读取一行
                            int i = 0;
                            while (!reader.EndOfStream)
                            {

                                i++;
                                //去掉之前相关信息
                                /*
                                    MicrosoftWindows [版本 5.2.3790]
                                    (C) 版权所有 1985-2003 Microsoft Corp.
                
                                   E:/Documents and Settings/Administrator>netstat -an
                
                                   Active Connections
                
                                     Proto  Local Address         Foreign Address        State
                                */
                                if (i > 9)
                                {

                                    if (strLine.Trim().Length > 0)
                                    {
                                        strLine = strLine.Trim();
                                        //Regex r = new Regex(@"/s+");
                                        string[] strArr = strLine.Split(new char[] {' '},
                                            StringSplitOptions.RemoveEmptyEntries);

                                        var localAddress = strArr[1].Substring(0, strArr[1].LastIndexOf(":"));
                                        var port = strArr[1].Substring(strArr[1].LastIndexOf(":") + 1,
                                            strArr[1].Length - strArr[1].LastIndexOf(":") - 1);
                                        if (strArr.Length == 5)
                                        {
                                            using (Process process = Process.GetProcessById(int.Parse(strArr[4])))
                                            {

                                                NetStatLine line = new NetStatLine()
                                                {
                                                    Protocol = strArr[0],
                                                    LocalAddress = localAddress,
                                                    Port = port,
                                                    ForeignAddress = strArr[2],
                                                    State = strArr[3],
                                                    PID = strArr[4],
                                                    ProcessName = process.ProcessName,

                                                };

                                                try
                                                {
                                                    line.ApplicationPath = process.MainModule.FileName;
                                                }
                                                catch (Exception ex)
                                                {

                                                }

                                                stateList.Add(line);
                                            }
                                        }
                                        else
                                        {
                                            using (Process process = Process.GetProcessById(int.Parse(strArr[3])))
                                            {

                                                NetStatLine line = new NetStatLine()
                                                {
                                                    Protocol = strArr[0],
                                                    LocalAddress = localAddress,
                                                    Port = port,
                                                    ForeignAddress = strArr[2],
                                                    State = string.Empty,
                                                    PID = strArr[3],
                                                    ProcessName = process.ProcessName

                                                };
                                                try
                                                {
                                                    line.ApplicationPath = process.MainModule.FileName;
                                                }
                                                catch (Exception ex)
                                                {

                                                }

                                                stateList.Add(line);
                                            }
                                        }
                                    }
                                }

                                strLine = reader.ReadLine(); //再下一行          
                            }

                            p.WaitForExit(); //等待程序执行完退出进程
                        }

                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                finally
                {
                    StopProcess();
                    sfDataGrid1.InvokeIfRequired(p =>
                    {
                        netStatLines = stateList.OrderBy(x => x.ProcessName).ThenBy(x => x.Port).ToList();
                        //sfDataGrid1.GroupColumnDescriptions.Clear();
                        p.DataSource = filterStatLines();

                    });
                    btnExport.InvokeIfRequired(p => p.Enabled = true);
                    btnRefresh.InvokeIfRequired(p => p.Enabled = true);
                }

            });
        }

        private List<NetStatLine> filterStatLines()
        {
            if (string.IsNullOrWhiteSpace(tbxFilter.Text))
            {
                return netStatLines;
            }
            else
            {
                string fileter = tbxFilter.Text.Trim().ToUpper();
                if (netStatLines != null)
                {
                    if (!chkExactMaching.Checked)
                    {

                        return netStatLines.Where(p => (!string.IsNullOrWhiteSpace(p.ApplicationPath) && p.ApplicationPath.ToUpper().Contains(fileter)) ||
                                                       (!string.IsNullOrWhiteSpace(p.Protocol) && p.Protocol.ToUpper().Contains(fileter)) ||
                                                       (!string.IsNullOrWhiteSpace(p.ForeignAddress) && p.ForeignAddress.ToUpper().Contains(fileter)) ||
                                                       (!string.IsNullOrWhiteSpace(p.LocalAddress) && p.LocalAddress.ToUpper().Contains(fileter)) ||
                                                       (!string.IsNullOrWhiteSpace(p.PID) && p.PID.ToUpper().Contains(fileter)) ||
                                                       (!string.IsNullOrWhiteSpace(p.Port) && p.Port.ToUpper().Contains(fileter)) ||
                                                       (!string.IsNullOrWhiteSpace(p.ProcessName) && p.ProcessName.ToUpper().Contains(fileter)) ||
                                                       (!string.IsNullOrWhiteSpace(p.State) && p.State.ToUpper().Contains(fileter))
                        ).ToList();
                    }
                    else
                    {
                        return netStatLines.Where(p => (!string.IsNullOrWhiteSpace(p.ApplicationPath) && p.ApplicationPath.ToUpper() == fileter) ||
                                                       (!string.IsNullOrWhiteSpace(p.Protocol) && p.Protocol.ToUpper() == fileter) ||
                                                       (!string.IsNullOrWhiteSpace(p.ForeignAddress) && p.ForeignAddress.ToUpper() == fileter) ||
                                                       (!string.IsNullOrWhiteSpace(p.LocalAddress) && p.LocalAddress.ToUpper() == fileter) ||
                                                       (!string.IsNullOrWhiteSpace(p.PID) && p.PID.ToUpper() == fileter) ||
                                                       (!string.IsNullOrWhiteSpace(p.Port) && p.Port.ToUpper() == fileter) ||
                                                       (!string.IsNullOrWhiteSpace(p.ProcessName) && p.ProcessName.ToUpper() == fileter) ||
                                                       (!string.IsNullOrWhiteSpace(p.State) && p.State.ToUpper() == fileter)
                        ).ToList();
                    }
                }
                else
                {
                    return null;
                }
            }
        }

        private bool IsProcessing;

        private void StartProcess()
        {
            IsProcessing = true;
            progressBar1.InvokeIfRequired(p => p.Visible = true);
            progressBar1.Value = 0;
            sfDataGrid1.ClearGrouping();
            sfDataGrid1.DataSource = null;
            Task.Factory.StartNew(() =>
            {
                while (IsProcessing)
                {
                    Thread.Sleep(300);
                    progressBar1.InvokeIfRequired(p =>
                    {
                        progressBar1.PerformStep();
                        if (progressBar1.Value == progressBar1.Maximum)
                        {
                            progressBar1.Value = 1;
                        }
                    });
                }
            });
        }

        private void StopProcess()
        {
            IsProcessing = false;
            progressBar1.InvokeIfRequired(p => p.Visible = false);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            GetNetStatData();
        }

        private void btnExport_Click(object sender, EventArgs e)
        {
            if (sfDataGrid1.DataSource != null)
            {
                SaveFileDialog sfd = new SaveFileDialog();
                ;

                sfd.Filter = "Csv File|*.csv";
                sfd.FileName = "NetStat_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".csv";

                if (sfd.ShowDialog() == DialogResult.OK)
                {

                    File.WriteAllLines(sfd.FileName,(sfDataGrid1.DataSource as List<NetStatLine>).Select<NetStatLine,string>(p =>
                        {
                            return string.Join(",", p.ProcessName, p.ApplicationPath, p.LocalAddress, p.Port,
                                p.ForeignAddress, p.Protocol, p.PID, p.State);
                        }).ToArray());
                }
            }
        }

     

        private void tbxFilter_KeyUp(object sender, KeyEventArgs e)
        {
            
                //sfDataGrid1.GroupColumnDescriptions.Clear();
                sfDataGrid1.DataSource = filterStatLines();
                

            
        }

        private void chkExactMaching_CheckedChanged(object sender, EventArgs e)
        {
            sfDataGrid1.DataSource = filterStatLines();

        }
    }


    public class NetStatLine
    {
        public string ProcessName { get; set; }
        public string Protocol { get; set; }
        public string LocalAddress { get; set; }
        public string Port { get; set; }
        public string ForeignAddress { get; set; }
        public string State { get; set; }
        public string PID { get; set; }
        public string ApplicationPath { get; set; }
    }
}
